// 首先实现MyPromise源码
// 要求：尽可能实现Promise中的每一个API，并通过注释的方式描述思路和原理

// 设置状态常量
const PENDING = 'pending';
const REJECT = 'reject';
const RESOLVE = 'resolve';

class MyPromise{
  // 一个初始的Promise状态为pending
  status = PENDING;
  // 成功执行异步动作后返回的值
  value = null;
  // reject的原因
  reason = null;
  // 成功执行resolve后的回调
  resolveCb = [];
  // reject后的回调
  rejectCb = [];
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
  resolve = (value) => {
    if(this.status === PENDING){
      // 设置状态为Reslove
      this.status = RESOLVE;
      this.value = value;
      // 调用resolve回调函数
      // this.resolveCb && this.resolveCb(this.value)
      while(this.resolveCb.length) {
        // 依次执行多个回调
        let cb = this.resolveCb.shift();
        cb && cb();
      }
    }
  }
  reject = (reason) =>{
    if(this.status === PENDING){
      // 设置状态为reject
      this.status = REJECT;
      this.reason = reason;
      // 调用resolve回调函数
      // this.rejectCb && this.rejectCb(reason)
      while(this.rejectCb.length) {
        // 依次执行多个回调
        let cb = this.rejectCb.shift();
        cb && cb()
      }
    }
  }
  then(resolveCb, rejectCb) {
    // 设置then默认参数，使得支持可变参数
    resolveCb = resolveCb ? resolveCb : value => value;
    rejectCb = rejectCb ? rejectCb : reason => {throw reason};
    let promise2 = new MyPromise((resolve, reject) => {
      if(this.status === RESOLVE) {
        setTimeout(() => {
          // 为了获得promise2的引用
          try {
            // executor里可能同步执行resolve
            let x = resolveCb(this.value);
            // 下一个promise
            // 判断x是普通值还是MyPromise对象
            // 如果是普通值，则直接resolve
            // 如果是MyPromise，则根据x返回结果来判断执行resolve还是reject
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0)
      } else if(this.status === REJECT) {
        setTimeout(() => {
          // 为了获得promise2的引用
          try {
            // 同理，可能同步执行了reject
            let x = rejectCb(this.reason);
            reject(x);
          } catch (e) {
            reject(e);
          }
        }, 0)
      } else {
        // 异步的情况下，先把回调函数存储起来
        // 使用数组支持多个回调
        this.resolveCb.push(() => {
          setTimeout(() => {
            // 为了获得promise2的引用
            try {
              // executor里可能同步执行resolve
              let x = resolveCb(this.value);
              // 下一个promise
              // 判断x是普通值还是MyPromise对象
              // 如果是普通值，则直接resolve
              // 如果是MyPromise，则根据x返回结果来判断执行resolve还是reject
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0)
        });
        this.rejectCb.push(() => {
          setTimeout(() => {
            // 为了获得promise2的引用
            try {
              // executor里可能同步执行resolve
              let x = rejectCb(this.reason);
              // 下一个promise
              // 判断x是普通值还是MyPromise对象
              // 如果是普通值，则直接resolve
              // 如果是MyPromise，则根据x返回结果来判断执行resolve还是reject
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0)
        });
      }
    });
    // 返回myPromise 支持链式调用
    return promise2;
  }
  finally(callback) {
    return this.then((value) => {
      let x = callback();
      return MyPromise.resolve(x).then(() => value)
    }, (reason) => {
      let x = callback();
      return MyPromise.resolve(x).then(() => {throw reason})
    })
  }
  catch(rejectCb){
    return this.then(null, rejectCb);
  }
  static all(pList) {
    const result = [];
    return new MyPromise((resolve, reject) => {
      let count = 0;
      function addResult(key, value) {
        result[key] = value;
        count++;
        if(count === pList.length) {
          // 说明所有promise执行完毕，支持异步
          resolve(result);
        }
      }
      for(let i=0; i<pList.length; i++) {
        const p = pList[i];
        if(p instanceof MyPromise) {
          // MyPromise 对象
          p.then(value => addResult(i, p), reason => reject(reason))
        } else {
          // 普通值则直接返回
          addResult(i, p);
        }
      }
    })
  }

  static resolve(value) {
    if(value instanceof MyPromise) {
      // MyPromise对象则直接返回
      return value;
    }
    return new MyPromise((resolve) => {
      resolve(value)
    })
  }
}

function resolvePromise(promise, val, resolve, reject) {
  if(promise === val) {
    // 防止循环调用自身
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if(val instanceof MyPromise) {
    val.then(resolve, reject)
  } else {
    resolve(val)
  }
}

/** 测试返回自身*/
// let p1 = new MyPromise((resolve, reject) => {
//   setTimeout(() => {
//     resolve(1)
//   })
// }).then((val) => {
//   console.log(val);
//   return p1;
// }, (error)=>{
//   console.log(error)
// })
// p1.then((val) => {
//   console.log(val);
// }, (error)=>{
//   console.log(error)
// })

/** all测试 */
// let p1 = new MyPromise((resolve, reject) => {
//   setTimeout(function() {
//     resolve('p1');
//   }, 1000);
// });
//
// let p2 = new MyPromise((resolve, reject) => {
//   setTimeout(function() {
//     resolve('p2');
//   }, 3000);
// });
//
// MyPromise.all(['1', 2, p1, p2])
//     .then((val) => console.log(val))

/*#region 测试finally */
// let p1 = new MyPromise((resolve, reject) => {
//   reject('p1 reject')
// })
//
// let p2 = new MyPromise((resolve, reject) => {
//   setTimeout(()=>{
//     resolve('p2 resolve')
//   }, 2000)
// })
//
// p1.finally(() => {
//   console.log('finally');
//   return p2;
// }).then((value) => {
//   console.log(value)
// }, (e) => {
//   console.log(e)
// })

// let p1 = new Promise((resolve, reject) => {
//   resolve(1)
// });
// p1.then((val) => {
//   console.log(val);
//   return p1;
// }).catch((error)=>{
//   console.log(error)
// })
